import { createDep } from "./dep";
import { attackToGlobal } from "../utils/index";

// 当前活动的effect
let activeEffect = undefined;

// 记录是否应该执行响应式追踪
let shouldTrack = false;

// 存储涉及到的所有target
const targetMap = new WeakMap();

// 简单检测一下是否应该执行追踪
export function isTracking() {
  return shouldTrack && activeEffect !== undefined;
}

export class ReactiveEffect {
  active = true;
  deps = []; // 存储的是set对象,set对象内存储的是与当前相关的effect
  constructor(public fn, public schedules?, public onstop?) {
    console.log("创建 ReactiveEffect 对象");
  }

  get dirty() {}
  set dirty(v) {}
  run() {
    console.log("run...");

    // 执行一次fn, 使用active控制是否应该触发追踪
    if (!this.active) {
      return this.fn();
    }

    // 保留现场
    const lastEffect = activeEffect;
    shouldTrack = true;
    activeEffect = this;

    const res = this.fn();

    shouldTrack = false;
    // 上一次的现场还原
    activeEffect = lastEffect;

    return res;
  }
  stop() {
    if (this.active) {
      // 清除依赖
      cleanupEffect(this);
      if (this.onstop) {
        this.onstop();
      }

      this.active = false;
    }
  }
}

// 清除给定的effect的dep
function cleanupEffect(effect: ReactiveEffect) {
  effect.deps.forEach((dep) => {
    dep.delete(effect);
  });
  effect.deps.length = 0;
}

export function track(target, type, key) {
  if (!isTracking()) {
    return;
  }

  console.log(`触发 track -> target: ${target} type:${type} key:${key}`);

  // targetMap => key: 当前对象 value: depsMap {} -> key: 当前对象修改的key value: Dep(Map)
  // Dep => key: 当前effect value: effect._trackId
  // 拿到当前target涉及到的所有的依赖项
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    depsMap = new Map();
    targetMap.set(target, depsMap);
  }
  // 拿到当前target中的某个属性涉及到的依赖项
  let dep = depsMap.get(key);
  if (!dep) {
    dep = createDep();
    depsMap.set(key, dep);
  }
  trackEffect(dep);
}

export function trackEffect(dep) {
  // 给当前的effect中保存涉及到的参数
  // 同时给涉及到的参数中保存当前的effect
  // 这就是 当前的effect <=> 涉及到的参数 相互绑定/相互记录
  if (!dep.has(activeEffect)) {
    dep.add(activeEffect);
    activeEffect.deps.push(dep);
  }
}

export function trigger(target, type, key, newValue, oldValue) {
  // 拿到当前key涉及的所有effect,然后触发它
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  const dep = depsMap.get(key);
  let deps = [];
  deps.push(dep);
  // 汇总所有涉及到的effect
  const effects = [];
  deps.forEach((dep) => {
    effects.push(...dep);
  });
  triggerEffect(createDep(effects));
}

export function triggerEffect(effects: Array<ReactiveEffect>) {
  for (const effect of effects) {
    if (effect.schedules) {
      effect.schedules();
    } else {
      effect.run();
    }
  }
}

export function effect(fn, options) {
  const _effect = new ReactiveEffect(fn);

  _effect.run();

  const runner = _effect.run.bind(_effect);
  runner.effect = _effect;

  // 对外返回一个运行器,允许在外部手运行
  return runner;
}
